package service

import (
	"encoding/json"
	"errors"
	"log"
	"net/http"
	"time"

	"coupons/config"
	"coupons/router/middleware"
	"coupons/types"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v4"
	"github.com/gorilla/websocket"
	"gorm.io/gorm"
)

// WebSocket升级器
var upgrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true // 允许所有跨域请求
	},
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

// 类型别名，方便使用
type VoucherNotification = types.VoucherNotification
type WebSocketMessage = types.WebSocketMessage

// Hub 管理所有活跃的客户端连接
type Hub = types.Hub

// Client 表示一个WebSocket客户端连接
type Client = types.Client

// NewHub 创建新的Hub实例
func NewHub(db *gorm.DB) *Hub {
	return &Hub{
		Clients:    make(map[*Client]bool),
		Broadcast:  make(chan []byte),
		Register:   make(chan *Client),
		Unregister: make(chan *Client),
		DB:         db,
	}
}

// RunHub 启动Hub的消息循环
func RunHub(h *Hub) {
	for {
		select {
		case client := <-h.Register:
			h.Mu.Lock()
			h.Clients[client] = true
			h.Mu.Unlock()
			log.Printf("客户端 %d 已连接", client.UserId)

		case client := <-h.Unregister:
			h.Mu.Lock()
			if _, ok := h.Clients[client]; ok {
				delete(h.Clients, client)
				close(client.Send)
			}
			h.Mu.Unlock()
			log.Printf("客户端 %d 已断开", client.UserId)

		case message := <-h.Broadcast:
			h.Mu.RLock()
			for client := range h.Clients {
				select {
				case client.Send <- message:
				default:
					close(client.Send)
					delete(h.Clients, client)
				}
			}
			h.Mu.RUnlock()
		}
	}
}

// HandleWebSocket 处理WebSocket连接
func HandleWebSocket(h *Hub, c *gin.Context) {
	// 从query参数获取token并解析用户ID
	token := c.Query("token")
	if token == "" {
		log.Printf("WebSocket连接失败: 缺少token参数")
		c.JSON(401, gin.H{"error": "缺少token参数"})
		return
	}

	// 解析JWT token获取用户ID
	userId, err := parseTokenForUserId(token)
	if err != nil {
		log.Printf("WebSocket连接失败: token解析失败 - %v", err)
		c.JSON(401, gin.H{"error": "token无效"})
		return
	}

	// 升级HTTP连接为WebSocket连接
	conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
	if err != nil {
		log.Printf("WebSocket升级失败: %v", err)
		return
	}

	// 创建客户端
	client := &Client{
		Conn:   conn,
		UserId: userId,
		Send:   make(chan []byte, 256),
		Hub:    h,
	}

	// 注册客户端
	h.Register <- client

	// 启动读写协程
	go writePump(client)
	go readPump(client)
}

// readPump 读取客户端消息
func readPump(c *Client) {
	defer func() {
		c.Hub.Unregister <- c
		c.Conn.Close()
	}()

	c.Conn.SetReadLimit(1024)
	c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
	c.Conn.SetPongHandler(func(string) error {
		c.Conn.SetReadDeadline(time.Now().Add(60 * time.Second))
		return nil
	})

	for {
		_, message, err := c.Conn.ReadMessage()
		if err != nil {
			if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) {
				log.Printf("WebSocket错误: %v", err)
			}
			break
		}

		// 处理客户端消息（心跳等）
		log.Printf("收到消息: %s", string(message))
	}
}

// writePump 向客户端发送消息
func writePump(c *Client) {
	ticker := time.NewTicker(54 * time.Second)
	defer func() {
		ticker.Stop()
		c.Conn.Close()
	}()

	for {
		select {
		case message, ok := <-c.Send:
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if !ok {
				c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			c.Conn.WriteMessage(websocket.TextMessage, message)

		case <-ticker.C:
			c.Conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
			if err := c.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		}
	}
}

// BroadcastVoucher 广播优惠券通知
func BroadcastVoucher(h *Hub, notification *VoucherNotification) {
	notification.Timestamp = time.Now().Unix()

	message := WebSocketMessage{
		Type: "voucher_notification",
		Data: notification,
	}

	data, err := json.Marshal(message)
	if err != nil {
		log.Printf("序列化消息失败: %v", err)
		return
	}

	select {
	case h.Broadcast <- data:
		log.Printf("广播优惠券通知: %s", notification.Message)
	default:
		log.Println("广播通道已满，消息被丢弃")
	}
}

// parseTokenForUserId 解析JWT token获取用户ID
func parseTokenForUserId(tokenString string) (string, error) {
	cfg := config.GetConfig()
	token, err := jwt.ParseWithClaims(tokenString, &middleware.JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
		return []byte(cfg.JWT.Secret), nil
	})

	if err != nil {
		return "", err
	}

	if claims, ok := token.Claims.(*middleware.JWTClaims); ok && token.Valid {
		return claims.UserId, nil
	}

	return "", errors.New("token无效")
}
